/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = amqp_comm.c                                        */
/*  NOTE      =                                                    */
/*  DATE      = 2015/09/09 by geyh                                 */
/*******************************************************************/

#include <stdio.h>
#include <stdlib.h>

#include "frbyte_buffer.h"
#include "frcomm.h"
#include "frmem.h"
#include "frct_comm.h"
#include "frreport_comm.h"

#include "amqp_basedata_type.h"
#include "amqp_content.h"
#include "amqp_comm10.h"


/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_proto_header_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, L7session_amqp_private *p_st_session_private)
{
    int i_ret = 0;
    char arr_tmp[16];
    short s_tmp = 0;

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_session_private == NULL)
        return FR_FAIL;

    //获取版本信息    AMQP 1-0-0
    i_ret = bytebuff_get_bytes(p_st_data, arr_tmp, 4);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    if(memcmp(arr_tmp, "AMQP", 4) != 0)
        return FR_FAIL;

    //如果已经获取到版本信息 则不解析
    if(p_st_session_private->p_server != NULL)
        return FR_SUCC;

    arr_tmp[4] = ' ';

    //跳过 proto ID
    i_ret = bytebuff_skip(p_st_data, 1);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //version major
    i_ret = bytebuff_get_short(p_st_data, 1, (uint16_t *)&s_tmp, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    snprintf(arr_tmp + 5, 3, "%d-", s_tmp);

    //version major
    i_ret = bytebuff_get_short(p_st_data, 1, (uint16_t *)&s_tmp, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    snprintf(arr_tmp + 7, 3, "%d-", s_tmp);

    //version major
    i_ret = bytebuff_get_short(p_st_data, 1, (uint16_t *)&s_tmp, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    snprintf(arr_tmp + 9, 2, "%d", s_tmp);

//    p_st_session_private->p_server = frstrdup(arr_tmp);
//    if(p_st_session_private->p_server == NULL)
//        return FR_FAIL;

    return FR_SUCC;

}


int amqp_sasl_mechanisms_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, L7session_amqp_private *p_st_session_private)
{
    int i_ret = 0;
    int i_skip_len = 0;

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_session_private == NULL)
        return FR_FAIL;

    i_ret = amqp_skip_content (p_st_data, &i_skip_len);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_trans_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, st_amqp_private_data *p_st_private)
{
    int i_ret = 0;
    int i_skip_len = 0;


    if(p_st_data == NULL || p_st_body_data == NULL || p_st_private == NULL)
        return FR_FAIL;

    //arguments  list
    i_ret = amqp_add_arguments(p_st_data, p_st_body_data, p_st_private);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 3);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //mess_header
    i_ret = amqp_add_mess_header(p_st_data, p_st_body_data, p_st_private);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 3);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //mess_properties
    i_ret = amqp_add_mess_properties(p_st_data, p_st_body_data, p_st_private);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 3);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //application properties
    i_ret = amqp_skip_content(p_st_data, &i_skip_len);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 3);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //mess content
    i_ret = amqp_add_mess_content(p_st_data, p_st_body_data, p_st_private);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 3);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    //footer
    i_ret = amqp_skip_content(p_st_data, &i_skip_len);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    return FR_SUCC;

}


/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_disposition_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, st_amqp_private_data *p_st_private)
{
    int i_ret = 0;

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_private == NULL)
        return FR_FAIL;

    i_ret = amqp_add_disposition(p_st_data, p_st_body_data, p_st_private);

    return i_ret;

}


/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_sasl_init_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, L7session_amqp_private *p_st_session_private)
{
    int i_ret = 0;

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_session_private == NULL)
        return FR_FAIL;

    p_st_session_private->i_flag_data_type = FRLOGIN_START;
    i_ret = amqp_get_username(p_st_data, p_st_body_data, p_st_session_private);

    return i_ret;

}


/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_sasl_outcome_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, st_amqp_private_data *p_st_private, L7session_amqp_private *p_st_session_private)
{
    int i_ret = 0;

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_private == NULL || p_st_session_private == NULL)
        return FR_FAIL;

    //response code
    i_ret = amqp_get_responsecode(p_st_data, p_st_body_data, p_st_private, &p_st_session_private->i_flag_data_type);

    return i_ret;

}


/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_close_parse_1_0_0(Frbyte_Packet *p_st_data)
{
    int i_ret = 0;
    int i_skip_len = 0;

    if(p_st_data == NULL)
        return FR_FAIL;

    i_ret = amqp_skip_content (p_st_data, &i_skip_len);

    return i_ret;

}

/*******************************************************************************
*  FUNC     :  判断是否是amqp
*  ARGS     :  p_st_data                    输入数据信息
*           :  p_st_body_data                 输入数据
*           :  p_st_private                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是activeMQ数据
*           :  APM_L7_IS_YES                是activeMQ数据
*  NOTE     :
*******************************************************************************/
int amqp_parse_1_0_0(Frbyte_Packet *p_st_data, Frreport_body_data *p_st_body_data, st_amqp_private_data *p_st_private, L7session_amqp_private *p_st_session_private)
{
    int i_ret = 0;
    unsigned int ui_all_len = 0;
    long long ll_type = 0;
    char arr_tmp[5];

    if(p_st_data == NULL || p_st_body_data == NULL || p_st_session_private == NULL)
        return APM_L7_ANALYZE_FAIL;

    if(p_st_data->ui_skip_len)
        return APM_L7_ANALYZE_TODO;

    //判断是否为protocol header
    i_ret = bytebuff_peek_bytes(p_st_data, arr_tmp, 4);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    if(memcmp(arr_tmp, "AMQP", 4) == 0)
    {
        p_st_private->i_flag_report = 0;
        i_ret = amqp_proto_header_parse_1_0_0(p_st_data, p_st_body_data, p_st_session_private);
        return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;
    }

    //获取长度
    i_ret = bytebuff_get_int(p_st_data, 4, &ui_all_len, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    //跳过不需要的信息
    i_ret = bytebuff_skip(p_st_data, 5);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    i_ret = amqp_get_long(p_st_data, &ll_type);
    if(i_ret == FR_FAIL)
        return APM_L7_ANALYZE_FAIL;

    switch (ll_type)
    {
        //Method: sasl.mechanisms (64)
        case 0x40:
            i_ret = amqp_sasl_mechanisms_parse_1_0_0 (p_st_data, p_st_body_data, p_st_session_private);
            p_st_private->i_flag_report = 0;
            break;
        //sasl.init
        case 0x41:
            i_ret = amqp_sasl_init_parse_1_0_0(p_st_data, p_st_body_data, p_st_session_private);
            p_st_private->i_flag_report = 0;
            break;

        case 0x44:
            i_ret = amqp_sasl_outcome_parse_1_0_0(p_st_data, p_st_body_data, p_st_private, p_st_session_private);
            p_st_private->i_flag_report = 0;
            break;

        case 0x14:
            i_ret = amqp_trans_parse_1_0_0(p_st_data, p_st_body_data, p_st_private);
            p_st_private->i_flag_report = 1;
            p_st_private->is_message = 1;
            break;

        case 0x15:
            i_ret = amqp_disposition_parse_1_0_0(p_st_data, p_st_body_data, p_st_private);
            p_st_private->is_message = 0;
            break;

        case 0x18:
            p_st_session_private->i_flag_data_type = FRLOGOUT_END;
            i_ret = amqp_close_parse_1_0_0 (p_st_data);
            break;

        default:
            p_st_private->i_flag_report = 0;
            if(ui_all_len < 11)
                return APM_L7_ANALYZE_FAIL;
            ui_all_len -= 11;

            if(ui_all_len <= p_st_data->ui_remaining)
            {
                i_ret = bytebuff_skip (p_st_data, ui_all_len);
                p_st_private->i_flag_report = 0;

                return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;
            }
            else
            {
                //skip
                i_ret = bytebuff_set_skip(p_st_data, ui_all_len - p_st_data->ui_remaining);
                if(i_ret == FR_FAIL)
                    return APM_L7_ANALYZE_FAIL;

                i_ret = bytebuff_skip (p_st_data, p_st_data->ui_remaining);
                p_st_private->i_flag_report = 0;

                return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;
            }

    }

    return i_ret == FR_SUCC ? APM_L7_ANALYZE_SUCC : APM_L7_ANALYZE_FAIL;

}
